#ifndef COMPOSITENODE_H
#define COMPOSITENODE_H

#pragma once

#include <list>

#include <LDF/LargeDisplayFrameworkLayer.h>

/**
 * This class implements a node in a composite design pattern.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since June 25, 2007
 */
class LARGEDISPLAYFRAMEWORKLAYER_API CompositeNode
{
	// Attributes
protected:
	/** The parent of this node. NULL if this is a root node. */
	CompositeNode* parent;
	/** The list of children of this node. NULL if this is a leaf node. */
	std::list<CompositeNode*> children;
	/** Flag indicating if this node is a leaf. */
	bool leaf;

	// Methods
public:
	CompositeNode(void);
	virtual ~CompositeNode(void);

	/**
	 * Adds the given node as a child to this one and updates the parent
	 * pointer in the child node. If this node is marked as a leaf or is the
	 * same as the this one, nothing is done.
	 *
	 * @param node the node to be added as a child.
	 */
        inline virtual void addChild(CompositeNode* node) {
                if (!leaf && node != this) { children.push_front(node); node->setParent(this); }
        };
	
	/**
	 * Adds the given list of nodes as children of this node. If this node is
	 * marked as a leaf, nothing is done.
	 *
	 * @param nodes a list of nodes to be made children of this node.
	 */
	void addChildren(std::list<CompositeNode*> nodes);
	/**
	 * Removes the child at the given index. If this node is marked as a leaf,
	 * nothing is done.
	 *
	 * @param child the child to be removed.
	 */
	inline void removeChild(CompositeNode* child) { if (!leaf) children.remove(child); };
	/**
	 * Removes all children of this node. If this node is marked as a leaf,
	 * nothing is done.
	 */
	inline void removeAllChildren() { if (!leaf) children.clear(); };
	/**
	 * Moves the specified child to the front of the children list. if the
	 * given component is not a child, it is added at the front of the children
	 * list. If this node is marked as a leaf, nothing is done.
	 *
	 * @param child the child to be moved to the front of the children list.
	 */
	inline void moveChildToFront(CompositeNode* child) {
		if (!leaf && children.front() != child) { children.remove(child); children.push_front(child); }
	};
	/**
	 * Moves this node to the front of its parent children list and propagates
	 * this change up to the root of composition.
	 */
	virtual void moveNodeToFront();
	/**
	 * Moves this node to be a child of the given parent. It is different from
	 * the addChild() method in the sense that this method removes this node
	 * from its previous parent children list, adds it to new parent children
	 * list, and updates this node parent link. If the given parent node is
	 * NULL or if the given parent node is the same as this node current
	 * parent, nothing is done.
	 *
	 * @param parentNode the node that will be made the parent of this one.
	 */
	virtual void moveNodeTo(CompositeNode* parentNode);


	// ACCESSOR METHODS
	/**
	 * Returns a pointer to the parent of this node.
	 *
	 * @return a pointer to the parent of this node.
	 */
	inline CompositeNode* getParent() { return parent; };
	/**
	 * Sets the parent of this node, as long as the given node is not this one.
	 *
	 * @param node a pointer to the node to be made the parent of this one.
	 */
	inline void setParent(CompositeNode* node) { if (node != this) parent = node; };
	/**
	 * Returns the list of children of this node.
	 *
	 * @return the list of children of this node.
	 */
	inline std::list<CompositeNode*> getChildren() { return children; };
	/**
	 * Sets the children of this node. If this node is marked as a leaf,
	 * nothing is done.
	 *
	 * @param nodes the list of nodes to be set as the children of this node.
	 */
	inline void setChildren(std::list<CompositeNode*> nodes) {
		if (!leaf) children = nodes;
	};
	/**
	 * Returns a pointer to the child of this node at the given index.
	 *
	 * @param index the index of the child
	 * @return a pointer to the child node at the given index.
	 */
//	inline CompositeNode* getChild(int index) { return children[index]; };
	/**
	 * Sets the given node as a child of this node at the given index.
	 *
	 * @param node the node to be made a child of this node.
	 * @param index the index of the child being set.
	 */
//	inline void setChild(CompositeNode* node, int index) { children[index] = node; };
	/**
	 * Returns true if this node is a leaf.
	 *
	 * @return true if this node is a leaf, false otherwise.
	 */
	inline bool isLeaf() { return leaf; };
	/**
	 * Sets this node to be a leaf or not.
	 *
	 * @param state true if this node is supposed to be a leaf, false otherwise.
	 */
	inline void setLeaf(bool state) { leaf = state; };
	
};

#endif // COMPOSITENODE_H
